/*
 * 创建日期 2010-5-12
 *
 * 成都天和软件公司
 * 电话：028-85425861
 * 传真：028-85425861-8008
 * 邮编：610041 
 * 版权所有
 */
package  org.fantasy.common.compile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import  org.fantasy.common.util.Debug;
import  org.fantasy.common.util.ThreadMap;
import  org.fantasy.common.util.WebContext;

/**
 *  Java动态编译
 * @author: 王文成
 * @version: 1.0
 * @since 2010-5-12
 */
public class SqlCompilerJava implements SqlCompiler {

    private static final Log log = LogFactory.getLog(SqlCompilerJava.class);

    private String packageName;

    private String superClass = " org.fantasy.common.compile.SqlBuilder";


    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    public void setSuperClass(String superClass) {
        this.superClass = superClass;
    }

    /**
    * 编译返回SqlBuilder
    * @param sqlCode
    * @return
    * @throws Exception
    */
    public SqlBuilder compile(final String sqlCode) throws Exception {
        log.info("################ Class Dir[" + getClassDir() + "] #################");
        File file = null;
        try {
            Debug debug = new Debug("Dyna Complie");
            debug.start("ComplieFile");
            file = createFile(sqlCode);
            String result = compileFile(file);
            // 编译结果0标识成功,编译错误返回NULL
            if (!"0".equals(result)) {
                //保存错误信息
                ThreadMap.put(CompileStatics.COMPILE_INFO,result);
                throw new Exception("Java编译出错:" + result + "\n" + sqlCode);
            }
            debug.end("ComplieFile");
            log.info(debug);
            return createInstance(file);
        } catch (Exception e) {
            log.error(e);
            throw new Exception("【" + sqlCode + "】", e);
        } finally {
            removeTempFile(file);
        }
    }

    /**
     * 创建Java文件
     * 
     * @param sqlCode
     * @return
     * @throws Exception
     */
    private File createFile(String sqlCode) throws Exception {
        File dir = new File(getClassDir());
        if (!dir.exists())
            dir.mkdir(); // 如果目录不存在就创建目录
        File file = File.createTempFile("RunTime", ".java", dir);
        String name = file.getName();
        String classname = name.substring(0, name.lastIndexOf('.'));
        PrintWriter out = null;
        try {
            out = new PrintWriter(new FileOutputStream(file));
            StringBuffer code = new StringBuffer(1024);
            code.append("\npackage " + packageName + "; \n");
            code.append("public class " + classname + " implements " + superClass + "{\n");
            code.append("   public String getSql(java.util.Map map) throws Exception{ \n");
            code.append("        org.fantasy.common.util.ResultMap rm = new  org.fantasy.common.util.ResultMap(map); \n");
            code.append("       " + sqlCode + " \n");
            code.append("       return sql.toString();\n");
            code.append("   }\n");
            code.append("}\n");
            out.println(code);
            log.info(code);
            out.flush();
        } finally {
            out.close();
        }
        return file;
    }

    /**
     * 编译文件
     * 
     * @param file
     * @throws Exception
     */
    private String compileFile(File file) throws Exception {
        String classPath = getClassPath();
        String[] arg = { "-classpath", classPath, "-d", classPath, file.getAbsolutePath() };
        StringWriter writer = new StringWriter(1024);
        int code = com.sun.tools.javac.Main.compile(arg, new PrintWriter(writer));
        return code == 0 ? "0" : writer.toString();
    }

    /**t
     * 创建实例
     * 
     * @param file
     * @return
     * @throws Exception
     */
    private SqlBuilder createInstance(File file) throws Exception {
        String filename = file.getName();
        String classname = filename.substring(0, filename.lastIndexOf('.'));
        return (SqlBuilder) Class.forName(packageName + "." + classname).newInstance();
    }

    /**
     * 删除临时文件
     * 
     * @param file
     * @throws Exception
     */
    private void removeTempFile(File file) throws Exception {
        String classDir = getClassDir();
        int last = file.getName().lastIndexOf('.');
        String name = file.getName().substring(0, last);
        String classFile = classDir + "/" + name + ".java";
        String javaFile = classDir + "/" + name + ".class";
        new File(javaFile).delete();
        new File(classFile).delete();
    }


    /**
     * 取得Class路径
     * 
     * @return
     */
    private String getClassPath() {
        return WebContext.getServletContext().getRealPath("/WEB-INF/classes");
    }

    /**
     * 取得Java路径
     * 
     * @return
     */
    private String getClassDir() {
        return getClassPath() + "/" + packageName;
    }
}
